home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
- *
- */
- #import "ProAudioSpectrum16.h"
- #import "ProAudioSpectrum16Registers.h"
- #import "ProAudioSpectrum16Inline.h"
-
- #import <driverkit/generalFuncs.h>
-
- static char pasDeviceName[] = "ProAudioSpectrum16";
- static char pasDeviceKind[] = "Audio";
-
- @implementation ProAudioSpectrum16
-
- /*
- * Probe and initialize new instance
- */
- + (BOOL) probe:description
- {
- ProAudioSpectrum16 *dev;
-
- dev = [self alloc];
- if (dev == nil)
- return NO;
-
- /*
- * Sets the base IO address (needs to be performed before any other
- * hardware access)
- */
- setBaseAddress(DEFAULT_BASE_ADDRESS);
-
- return [dev initFromDeviceDescription:description] != nil;
- }
-
- - (BOOL) reset
- {
- IOReturn ioReturn;
- unsigned int dmaChannel = [[self deviceDescription] channel];
- unsigned int interrupt = [[self deviceDescription] interrupt];
- IOEISADMATransferWidth transferWidth = IO_16BitByteCount;
-
- [self setName: pasDeviceName];
- [self setDeviceKind: pasDeviceKind];
-
- if (! (resetHardware())) {
- IOLog("%s: hardware failed verification\n", [self name]);
- return NO;
- }
-
- /*
- * The irq and dma channel are software selectable on the
- * ProAudioSpectrum16.
- */
- if (! (setDMAChannel(dmaChannel))) {
- IOLog("%s: %d is an invalid dma setting\n",
- [self name], dmaChannel);
- return NO;
- }
-
- if (! (setInterrupt(interrupt))) {
- IOLog("%s: %d is an invalid irq setting\n",
- [self name], interrupt);
- return NO;
- }
-
- /*
- * The DMA controller is initialized.
- */
- [self disableChannel: 0];
-
- /*
- * On both ISA and EISA machines, the ProAudioSpectrum16 hardware
- * requires that DMA channels 0-4 are set to an 8-bit transfer width.
- */
- if ([self isEISAPresent]) {
- if (dmaChannel < 5)
- transferWidth = IO_8Bit;
-
- ioReturn = [self setDMATransferWidth: transferWidth forChannel: 0];
- if (ioReturn != IO_R_SUCCESS) {
- IOLog("%s: dma transfer width error %d\n", [self name], ioReturn);
- return NO;
- }
- }
-
- ioReturn = [self setTransferMode: IO_Single forChannel: 0];
-
- if (ioReturn != IO_R_SUCCESS) {
- IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
- return NO;
- }
-
- ioReturn = [self setAutoinitialize: YES forChannel: 0];
- if (ioReturn != IO_R_SUCCESS) {
- IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
- return NO;
- }
-
- return YES;
- }
-
- /*
- * converts gain (0 - 32768) into attenuation (0 - 31)
- */
-
- - (void) updateInputGainLeft
- {
- unsigned int gain = [self inputGainLeft] / 1057;
-
- setInputAttenuation(MICROPHONE, LEFT_CHANNEL, (unsigned char) gain);
- setInputAttenuation(EXTERNAL_LINE_IN, LEFT_CHANNEL, (unsigned char) gain);
- }
-
- - (void)updateInputGainRight
- {
- unsigned int gain = [self inputGainRight] / 1057;
-
- setInputAttenuation(MICROPHONE, RIGHT_CHANNEL, (unsigned char) gain);
- setInputAttenuation(EXTERNAL_LINE_IN, RIGHT_CHANNEL, (unsigned char) gain);
- }
-
- - (void)updateOutputMute
- {
- enableAudioOutput(! [self isOutputMuted]);
- }
-
- - (void)updateLoudnessEnhanced
- {
- setLoudnessFilter([self isLoudnessEnhanced]);
- }
-
- /*
- * (0) - (-84) needs to be converted to (0) - (31)
- */
- - (void) updateOutputAttenuationLeft
- {
- unsigned int attenuation = [self outputAttenuationLeft] + 84;
- attenuation = ((attenuation * 10)/27);
-
- setOutputAttenuation(PCM, LEFT_CHANNEL, (unsigned char) attenuation);
- }
-
- /*
- * (0) - (-84) needs to be converted to (0) - (32)
- */
- - (void) updateOutputAttenuationRight
- {
- unsigned int attenuation = [self outputAttenuationRight] + 84;
- attenuation = ((attenuation * 10)/27);
-
- setOutputAttenuation(PCM, RIGHT_CHANNEL, (unsigned char) attenuation);
- }
-
- - (IOReturn) enableAllInterrupts
- {
- interruptStatus_t interruptStatus = {0};
- interruptControl_t interruptControl = {0};
-
- /*
- * clear all interrupts
- */
- setInterruptStatus(interruptStatus);
-
- interruptControl.enableSampleBufferInterrupt = YES;
- setInterruptControl(interruptControl);
-
- return [super enableAllInterrupts];
- }
-
- - (void) disableAllInterrupts
- {
- interruptControl_t interruptControl = {0};
-
- setInterruptControl(interruptControl);
-
- [super disableAllInterrupts];
- }
-
-
- - (BOOL) startDMAForChannel: (unsigned int) localChannel
- read: (BOOL) isRead
- buffer: (IOEISADMABuffer) buffer
- bufferSizeForInterrupts: (unsigned int) bufferSize
- {
-
- IOReturn ioReturn;
- unsigned int rate = [self sampleRate];
-
- IOEISADMATransferWidth transferWidth;
-
- filterControl_t filterControl = {0};
- crossChannelControl_t crossChannelControl = {0};
- systemConfiguration2_t systemConfiguration2 = {0};
-
-
- /*
- * Before enabling the DMA channel, "secure" the channel via the DRQ
- * bit in the Cross Channel register (0xf8a). This causes the
- * ProAudioSpectrum16 to drive the DMA channel from a floating state to
- * a known good state. If you enable the DMA channel with an unsecured
- * DRQ line, the DMA will perform a rapid-fire data tranfer due to the
- * floating DRQ line.
- */
- crossChannelControl = getCrossChannelControl();
- crossChannelControl.enableDMA = YES;
- setCrossChannelControl(crossChannelControl);
-
- ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
-
- if (ioReturn != IO_R_SUCCESS) {
- IOLog("%s: could not start DMA channel error %d\n",
- [self name], ioReturn);
- return NO;
- }
-
- ioReturn = [self enableChannel: localChannel];
-
- if (ioReturn != IO_R_SUCCESS) {
- IOLog("%s: could not enable DMA channel error %d\n",
- [self name], ioReturn);
- return NO;
- }
-
- (void) [self enableAllInterrupts];
-
- setSampleRateTimer(rate);
-
- /*
- * Use the Sample Buffer Count register to set the number of bytes in the
- * DMA buffer division. This register holds a 16-bit value. When using a
- * 16-bit DMA channel, the Sample Buffer Count must be divided by two.
- */
- (void) [self getDMATransferWidth: &transferWidth forChannel: localChannel];
- if (transferWidth == IO_16BitByteCount ||
- transferWidth == IO_16BitWordCount)
- setSampleBufferCounter(bufferSize / 2);
- else
- setSampleBufferCounter(bufferSize);
-
-
- if ([self dataEncoding] == NX_SoundStreamDataEncoding_Linear16)
- systemConfiguration2.dataEncoding = LINEAR_16;
- else
- systemConfiguration2.dataEncoding = LINEAR_8;
-
- setSystemConfiguration2(systemConfiguration2);
-
- crossChannelControl.rightToRight = YES;
- crossChannelControl.leftToLeft = YES;
-
- crossChannelControl.direction = !isRead;
-
- /*
- * The mixer has feedback problems. MediaVision advised us to mute
- * the PCM output channel when recording.
- */
- if (isRead)
- setOutputAttenuation(PCM, BOTH_CHANNELS, 0);
-
- if ([self channelCount] == 1)
- crossChannelControl.isMono = YES;
- else
- crossChannelControl.isMono = NO;
-
- setCrossChannelControl(crossChannelControl);
- crossChannelControl.enablePCM = YES;
- crossChannelControl.enableDMA = YES;
- setCrossChannelControl(crossChannelControl);
-
- filterControl = getFilterControl();
- filterControl.enableSampleRateTimer = YES;
- filterControl.enableSampleBufferCounter = YES;
- setFilterControl(filterControl);
-
- return YES;
- }
-
- - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
- {
- filterControl_t filterControl = {0};
- crossChannelControl_t crossChannelControl = {0};
-
- [self disableChannel: localChannel];
-
- filterControl = getFilterControl();
- filterControl.enableSampleRateTimer = NO;
- filterControl.enableSampleBufferCounter = NO;
- setFilterControl(filterControl);
-
- (void)[self disableAllInterrupts];
-
- crossChannelControl = getCrossChannelControl();
- crossChannelControl.enablePCM = NO;
- setCrossChannelControl(crossChannelControl);
- crossChannelControl.enableDMA = NO;
- setCrossChannelControl(crossChannelControl);
-
- /*
- * Due to mixer feedback problems, the PCM channels are muted during
- * recording. Their current values are restored here.
- */
- if (isRead) {
- [self updateOutputAttenuationLeft];
- [self updateOutputAttenuationRight];
- }
- }
-
- static void clearInterrupts(void)
- {
- interruptStatus_t interruptStatus = {0};
-
- /*
- * clear the hardware interrupt register
- */
- interruptStatus = getInterruptStatus();
- if (! interruptStatus.sampleBufferInterruptPending)
- return;
-
- /*
- * The chip specification states that a write to this register
- * will clear the clip status and sample interrupts.
- */
- interruptStatus.sampleBufferInterruptPending = NO;
- setInterruptStatus(interruptStatus);
- }
-
- - (IOAudioInterruptClearFunc) interruptClearFunc
- {
- return clearInterrupts;
- }
-
- - (void) interruptOccurredForInput: (BOOL*)serviceInput
- forOutput:(BOOL*)serviceOutput
- {
- interruptStatus_t interruptStatus = {0};
-
- /*
- * clear the hardware interrupt register
- */
- interruptStatus = getInterruptStatus();
- if (! interruptStatus.sampleBufferInterruptPending) {
- IOLog("ProAudioSpectrum16: spurious dma interrupt\n");
- return;
- }
-
- /*
- * The chip specification states that a write to this register
- * will clear the clip status and sample interrupts.
- */
- interruptStatus.sampleBufferInterruptPending = NO;
- setInterruptStatus(interruptStatus);
-
- if ([self isInputActive])
- *serviceInput = YES;
- else
- *serviceOutput = YES;
- }
-
- - (void) timeoutOccurred
- {
- crossChannelControl_t crossChannelControl = {0};
-
- crossChannelControl = getCrossChannelControl();
- crossChannelControl.enablePCM = NO;
- setCrossChannelControl(crossChannelControl);
- crossChannelControl.enablePCM = YES;
- setCrossChannelControl(crossChannelControl);
- }
-
- /*
- * Parameter access.
- */
-
- - (BOOL)acceptsContinuousSamplingRates
- {
- return YES;
- }
-
- - (void)getSamplingRatesLow: (int *)lowRate
- high: (int *)highRate
- {
- *lowRate = 2000;
- *highRate = 44100;
- }
-
- - (void)getSamplingRates: (int *)rates
- count: (unsigned int *)numRates
- {
- /* Return a few common rates */
- rates[0] = 2000;
- rates[1] = 8000;
- rates[2] = 11025;
- rates[3] = 16000;
- rates[4] = 22050;
- rates[5] = 32000;
- rates[6] = 44100;
- *numRates = 7;
- }
-
- - (void)getDataEncodings: (NXSoundParameterTag *)encodings
- count: (unsigned int *)numEncodings
- {
- IOEISADMATransferWidth transferWidth;
-
- encodings[0] = NX_SoundStreamDataEncoding_Linear8;
- encodings[1] = NX_SoundStreamDataEncoding_Linear16;
- *numEncodings = 2;
-
- /*
- * For EISA machines, the driver is unable to handle 16-bit linear data
- * when the DMA transfer width is 8 bits.
- */
- if ([self isEISAPresent]) {
- (void)[self getDMATransferWidth: &transferWidth forChannel: 0];
- if (transferWidth == IO_8Bit) {
- encodings[1] = 0;
- *numEncodings = 1;
- }
- }
- }
-
- - (unsigned int) channelCountLimit
- {
- return 2; /* stereo and mono */
- }
-
- @end
-